package com.xms.sdk.data;

import cn.hutool.core.lang.Assert;
import com.xms.core.data.Entity;
import com.xms.core.exception.XmsException;
import com.xms.core.model.PagedList;
import com.xms.datacore.SqlDescriptor;
import com.xms.datacore.provider.IDataRepositoryBase;
import com.xms.sdk.core.DynamicData;
import com.xms.sdk.core.RetrieverParameter;
import com.xms.sdk.core.query.QueryBase;
import com.xms.sdk.core.query.QueryExpression;
import com.xms.sdk.extensions.IQueryMetadataFinder;
import com.xms.sdk.query.IQueryResolverFactory;
import com.xms.sdk.query.QueryMetadataDescriptor;
import com.xms.sdk.query.QueryResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 组织数据查询器
 * </p>
 *
 * @author migo
 * @since 2021/9/5
 */
@Service
public class OrganizationDataRetriever implements IOrganizationDataRetriever {
    private IQueryResolverFactory _queryResolverFactory;
    private IDataRepositoryBase _dataRepositoryBase;
    private IQueryMetadataFinder _queryMetadataFinder;

    @Autowired
    public void OrganizationDataRetriever(IDataRepositoryBase dataRepositoryBase,
                                          IQueryMetadataFinder queryMetadataFinder,
                                          IQueryResolverFactory queryResolverFactory) {
        _dataRepositoryBase = dataRepositoryBase;
        _queryMetadataFinder = queryMetadataFinder;
        _queryResolverFactory = queryResolverFactory;
    }

    private <TEntity> QueryResult<TEntity> buildQueryResult(QueryBase query) {
        Assert.notNull(query);
        Assert.notBlank(query.EntityName);
        QueryResult<TEntity> result = new QueryResult<>();
        QueryMetadataDescriptor metadatas = _queryMetadataFinder.getAll(query);
        result.metadataDescriptor = metadatas;
        return result;
    }

    @Override
    public QueryResult<PagedList<Entity>> paged(RetrieverParameter parameters) throws Exception {
        QueryResult<PagedList<Entity>> queryResult = this.buildQueryResult(parameters.getQuery());
        QueryExpression queryExpression = (QueryExpression) parameters.getQuery();
        SqlDescriptor sql = _queryResolverFactory.getResolver(parameters.getQuery()).toSqlString(parameters, queryResult.metadataDescriptor);
        PagedList<DynamicData> result = _dataRepositoryBase.page(queryExpression.PageInfo.PageNumber, queryExpression.PageInfo.PageSize, sql);

        PagedList<Entity> pageResult = new PagedList<>(result.currentpage, result.itemsperpage, result.totalitems);
        List<Entity> items = new ArrayList<>();
        for (DynamicData item : result.items) {
            Entity entity = new Entity(parameters.getQuery().EntityName, item);
            items.add(entity);
        }
        pageResult.items = items;
        pageResult.totalpages = result.totalpages;
        queryResult.data = pageResult;
        return queryResult;
    }

    @Override
    public QueryResult<List<Entity>> list(RetrieverParameter parameters) throws SQLException, XmsException {
        QueryResult<List<Entity>> queryResult = this.buildQueryResult(parameters.getQuery());
        SqlDescriptor sql = _queryResolverFactory.getResolver(parameters.getQuery()).toSqlString(parameters, queryResult.metadataDescriptor);
        List<DynamicData> result = _dataRepositoryBase.query(sql);
        List<Entity> items = new ArrayList<>();
        for (DynamicData item : result) {
            Entity entity = new Entity(parameters.getQuery().EntityName, item);
            items.add(entity);
        }
        queryResult.data = items;
        return queryResult;
    }

    @Override
    public QueryResult<Entity> getOne(RetrieverParameter parameters) throws Exception {
        QueryResult<Entity> queryResult = this.buildQueryResult(parameters.getQuery());
        SqlDescriptor sql = _queryResolverFactory.getResolver(parameters.getQuery()).toSqlString(parameters, queryResult.metadataDescriptor);
        DynamicData data = _dataRepositoryBase.one(sql);
        if (data != null) {
            queryResult.data = new Entity(parameters.getQuery().EntityName, data);
        }
        return queryResult;
    }

    @Override
    public QueryResult<PagedList<DynamicData>> dynamicPaged(RetrieverParameter parameters) throws Exception {
        QueryResult<PagedList<DynamicData>> queryResult = this.buildQueryResult(parameters.getQuery());
        QueryExpression queryExpression = (QueryExpression) parameters.getQuery();
        SqlDescriptor sql = _queryResolverFactory.getResolver(parameters.getQuery()).toSqlString(parameters, queryResult.metadataDescriptor);
        queryResult.data = _dataRepositoryBase.page(queryExpression.PageInfo.PageNumber, queryExpression.PageInfo.PageSize, sql);

        return queryResult;
    }

    @Override
    public QueryResult<List<DynamicData>> dynamicList(RetrieverParameter parameters) throws SQLException, XmsException {
        QueryResult<List<DynamicData>> queryResult = this.buildQueryResult(parameters.getQuery());
        SqlDescriptor sql = _queryResolverFactory.getResolver(parameters.getQuery()).toSqlString(parameters, queryResult.metadataDescriptor);
        queryResult.data = _dataRepositoryBase.query(sql);

        return queryResult;
    }

    @Override
    public QueryResult<DynamicData> dynamicOne(RetrieverParameter parameters) throws Exception {
        QueryResult<DynamicData> queryResult = this.buildQueryResult(parameters.getQuery());
        SqlDescriptor sql = _queryResolverFactory.getResolver(parameters.getQuery()).toSqlString(parameters, queryResult.metadataDescriptor);
        queryResult.data = _dataRepositoryBase.one(sql);

        return queryResult;
    }
}
